             package com.java.diagnostics.visualizer.gc.iseriessupport.parser;
             
             import com.java.diagnostics.visualizer.data.DataLevel;
             import com.java.diagnostics.visualizer.data.SourceData;
             import com.java.diagnostics.visualizer.data.StructuredData;
             import com.java.diagnostics.visualizer.data.UnstructuredData;
             import com.java.diagnostics.visualizer.exceptions.GCAndMemoryVisualizerException;
             import com.java.diagnostics.visualizer.factory.DataFactory;
             import com.java.diagnostics.visualizer.factory.SourceDataFactory;
             import com.java.diagnostics.visualizer.gc.iseriessupport.util.Messages;
             import com.java.diagnostics.visualizer.impl.factory.LogFactory;
             import com.java.diagnostics.visualizer.parser.vgc.VGCDataManager;
             import com.java.diagnostics.visualizer.parser.vgc.VGCParserPreferenceHelper;
             import com.java.diagnostics.visualizer.parser.vgc.VGCPlainTextParser;
             import com.java.diagnostics.visualizer.parser.vgc.constants.VGCGCReasons;
             import com.java.diagnostics.visualizer.parser.vgc.sovereign.InstanceSovereignVGCParser;
             import com.java.diagnostics.visualizer.properties.OutputProperties;
             import com.java.diagnostics.visualizer.sources.Source;
             import java.io.BufferedReader;
             import java.util.Map;
             import java.util.TreeMap;
             import java.util.logging.Level;
             import java.util.logging.Logger;
             import java.util.regex.Matcher;
             import java.util.regex.Pattern;
             
             public class InstanceISeriesVGCParser
               extends VGCPlainTextParser
             {
               private static final String THRESHOLD_ALLOCATION_REACHED = "threshold allocation reached";
               private static final String MAXIMUM_HEAP_SIZE = Messages.getString("InstanceISeriesVGCParser.maximum.heap.size");
               
               private static final String INITIAL_HEAP_SIZE = Messages.getString("InstanceISeriesVGCParser.initial.heap.size");
               
               public static final String GC = "GC: ";
               
               private static final String VERSION = Messages.getString("ISeriesVGCParser.version");
               
               private static final Logger TRACE = LogFactory.getTrace(InstanceSovereignVGCParser.class);
               
               private static final double KILOBYTES_PER_BYTE = 0.0009765625D;
               
               private static final Pattern INITIAL_HEAP_PATTERN = Pattern.compile("GC: initial heap\\(KB\\) ([0-9]*); maximum heap\\(KB\\) ([0-9]*); virtual machine identifier ([A-F|0-9]*);  heap identifier ([A-F|0-9]*).");
               
               private static final Pattern AF_PATTERN = Pattern.compile("GC ([0-9]*): starting collection, (.*).");
               
               private static final Pattern START_PATTERN = Pattern.compile("GC ([0-9]*): collection starting ([0-9][0-9]/[0-9][0-9]/[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9])");
               
               private static final Pattern OBJECTS_PATTERN = Pattern.compile("GC ([0-9]*): live objects ([0-9]*); collected objects ([0-9]*); collected\\(KB\\) ([0-9]*).");
               
               private static final Pattern SOFT_REFERENCES_PATTERN = Pattern.compile("GC ([0-9]*): queued for finalization ([0-9]*); total soft references ([0-9]*); cleared soft references ([0-9]*).");
               
               private static final Pattern HEAP_PATTERN = Pattern.compile("GC ([0-9]*): current heap\\(KB\\) ([0-9]*); current threshold\\(KB\\) ([0-9]*).");
               
               private static final Pattern PAUSE_PATTERN = Pattern.compile("GC ([0-9]*): collect \\(milliseconds\\) ([0-9]*).");
               
               private static final Pattern ALLOCATION_PATTERN = Pattern.compile("GC ([0-9]*): current cycle allocation\\(KB\\) ([0-9]*); previous cycle allocation\\(KB\\) ([0-9]*).");
               
               private static final Pattern WEAK_REFERENCES_PATTERN = Pattern.compile("GC ([0-9]*): total weak references ([0-9]*); cleared weak references ([0-9]*).");
               
               private static final Pattern FINAL_REFERENCES_PATTERN = Pattern.compile("GC ([0-9]*): total final references ([0-9]*); cleared final references ([0-9]*).");
               
               private static final Pattern PHANTOM_REFERENCES_PATTERN = Pattern.compile("GC ([0-9]*): total phantom references ([0-9]*); cleared phantom references ([0-9]*).");
               
               private static final Pattern JNI_REFERENCES_PATTERN = Pattern.compile("GC ([0-9]*): total JNI global weak references ([0-9]*); cleared JNI global weak references ([0-9]*).");
               
               private static final Pattern CLASSES_PATTERN = Pattern.compile("GC ([0-9]*): collected class .*\\.");
               
               private static final Pattern END_PATTERN = Pattern.compile("GC ([0-9]*): collection ending ([0-9][0-9]/[0-9][0-9]/[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9])");
               
               private static final String INITIAL_HEAPS_LABEL = "InstanceISeriesVGCParser.initial.heap.properties";
               
               private String reasonString;
               
               private Map initialHeapMap;
               
               private int classesUnloaded = 0;
               private String unloadedClassComment = null;
               
               public SourceData parse(Source source, OutputProperties properties) throws GCAndMemoryVisualizerException
               {
                 TRACE.entering(this.className, "parse");
                 this.filterSystemGCs = PLUGIN_PREFERENCES.getFilterSystemGCs();
                 
                 this.isGoodData = false;
                 
                 initialiseAndClean();
                 
                 this.initialHeapMap = new TreeMap();
                 
                 try
                 {
                   String variantIdentifier = source.getVariantIdentifier();
                   this.sourceData = 
                     SOURCE_DATA_FACTORY.createSourceData(variantIdentifier);
                   this.dataManager = new VGCDataManager(source, this.sourceData, properties);
                   BufferedReader reader = source.getSafeBufferedStreamReader();
                   
                   String line = reader.readLine();
                   
                   while (line != null) {
                     handleLine(line, reader);
                     
                     line = reader.readLine();
                   }
                   
                   if (this.classesUnloaded > 0) {
                     this.dataManager.addPoint("VGCLabels.classes.unloaded", 
                       this.classesUnloaded, this.unloadedClassComment);
                     this.classesUnloaded = 0;
                     this.unloadedClassComment = null;
                   }
                   if (this.isGoodData) {
                     UnstructuredData versionData = factory.createUnstructuredData(
                       "VGCLabels.version", 
                       Messages.getString("VGCLabels.version"), VERSION);
                     this.sourceData.addData(versionData, DataLevel.VARIANT);
                     
                     writeOutSourceData();
                   }
                   this.dataManager.complete();
                   reader.close();
                 } catch (Exception e) {
                   TRACE.log(Level.WARNING, 
                     Messages.getString("ISeriesVGCParser.caught.exception"), e);
                   
                   this.sourceData = null;
                 }
                 TRACE.exiting(this.className, "parse");
                 return this.sourceData;
               }
               
               private void handleLine(String line, BufferedReader reader)
               {
                 Matcher reasonLine = AF_PATTERN.matcher(line);
                 
                 if (reasonLine.find())
                 {
                   this.reasonString = reasonLine.group(1);
                 } else {
                   Matcher start = START_PATTERN.matcher(line);
                   
                   if (start.find()) {
                     if (this.classesUnloaded > 0) {
                       this.dataManager.addPoint("VGCLabels.classes.unloaded", 
                         this.classesUnloaded, this.unloadedClassComment);
                       this.classesUnloaded = 0;
                       this.unloadedClassComment = null;
                     }
                     this.isGoodData = true;
                     
                     double gcNumber = Double.parseDouble(start.group(1));
                     double timestamp = ISeriesDateConverter.parseDate(start
                       .group(2));
                     this.dataManager.setX(timestamp);
                     this.currentGCNumber += 1;
                     if ((gcNumber == 1.0D) && (this.currentGCNumber > 1)) {
                       logRestart();
                     }
                     
                     if ((this.reasonString != null) && 
                       ("threshold allocation reached".equals(this.reasonString))) {
                       int reason = VGCGCReasons.AF_INT;
                       addDataPoint("VGCLabels.gc.reasons", reason, 
                         this.reasonString);
                     }
                     
                   }
                   else
                   {
                     Matcher heap = HEAP_PATTERN.matcher(line);
                     if (heap.matches())
                     {
                       double heapSize = Double.parseDouble(heap.group(2)) / 
                         0.0009765625D;
                       addDataPoint("VGCLabels.flat.heap.size", heapSize, line);
                       double live = heapSize - 
                         this.dataManager.getLastValue("VGCLabels.amount.freed");
                       addDataPoint("VGCLabels.live.normal.heap.after.gc", live, line);
                     }
                     else
                     {
                       Matcher pause = PAUSE_PATTERN.matcher(line);
                       if (pause.matches())
                       {
                         double pauseTime = Double.parseDouble(pause.group(2));
                         addDataPoint(
                           "VGCLabels.pause.times.without.exclusive.access", 
                           pauseTime, line);
                       } else {
                         Matcher allocations = ALLOCATION_PATTERN.matcher(line);
                         if (allocations.matches())
                         {
                           double allocation = Double.parseDouble(allocations
                             .group(2)) / 
                             0.0009765625D;
                           addDataPoint("VGCLabels.allocation.per.cycle", 
                             allocation, line);
                         }
                         else {
                           Matcher weakReferences = WEAK_REFERENCES_PATTERN
                             .matcher(line);
                           if (weakReferences.matches()) {
                             handleWeakReferencesLine(line, weakReferences);
                           }
                           else {
                             Matcher finalReferences = FINAL_REFERENCES_PATTERN
                               .matcher(line);
                             if (finalReferences.matches()) {
                               handleFinalReferencesLine(line, 
                                 finalReferences);
                             }
                             else {
                               Matcher softReferences = SOFT_REFERENCES_PATTERN
                                 .matcher(line);
                               if (softReferences.matches()) {
                                 handleSoftReferencesLine(line, 
                                   softReferences);
                               }
                               else
                               {
                                 Matcher phantomReferences = PHANTOM_REFERENCES_PATTERN
                                   .matcher(line);
                                 if (phantomReferences.matches()) {
                                   handlePhantomReferencesLine(line, 
                                     phantomReferences);
                                 }
                                 else
                                 {
                                   Matcher jniReferences = JNI_REFERENCES_PATTERN
                                     .matcher(line);
                                   if (jniReferences.matches()) {
                                     handleJNILine(line, 
                                       jniReferences);
                                   }
                                   else {
                                     Matcher objects = OBJECTS_PATTERN
                                       .matcher(line);
                                     if (objects.matches()) {
                                       handleObjectsLine(line, 
                                         objects);
                                     }
                                     else {
                                       Matcher classes = CLASSES_PATTERN
                                         .matcher(line);
                                       
                                       if (classes.matches()) {
                                         handleClassesLine(line);
                                       }
                                       else
                                       {
                                         Matcher initialHeaps = INITIAL_HEAP_PATTERN
                                           .matcher(line);
                                         
                                         if (initialHeaps.matches()) {
                                           handleInitialHeapsLine(initialHeaps);
                                         }
                                       }
                                     }
                                   }
                                 }
                               }
                             }
                           }
                         }
                       }
                     }
                   }
                 }
               }
               
               private void handleWeakReferencesLine(String line, Matcher weakReferences) {
                 double queued = Double.parseDouble(weakReferences.group(2));
                 double cleared = Double.parseDouble(weakReferences.group(3));
                 addDataPoint("VGCLabels.weak.references.cleared", cleared, line);
                 addDataPoint("VGCLabels.weak.references.queued", queued, line);
               }
               
               private void handleFinalReferencesLine(String line, Matcher finalReferences) {
                 double queued = Double.parseDouble(finalReferences.group(2));
                 double cleared = Double.parseDouble(finalReferences.group(3));
                 addDataPoint("VGCLabels.final.references.cleared", cleared, line);
                 addDataPoint("VGCLabels.final.references.queued", queued, line);
               }
               
               private void handleSoftReferencesLine(String line, Matcher softReferences) {
                 double finalization = Double.parseDouble(softReferences.group(2));
                 double queued = Double.parseDouble(softReferences.group(3));
                 double cleared = Double.parseDouble(softReferences.group(4));
                 addDataPoint("VGCLabels.soft.references.cleared", cleared, line);
                 addDataPoint("VGCLabels.soft.references.queued", queued, line);
                 addDataPoint("VGCLabels.objects.queued.for.finalization", finalization, 
                   line);
               }
               
               private void handleInitialHeapsLine(Matcher initialHeaps) {
                 Double initialHeap = new Double(initialHeaps.group(1));
                 Double maxHeap = new Double(initialHeaps.group(2));
                 this.initialHeapMap.put(INITIAL_HEAP_SIZE, initialHeap);
                 this.initialHeapMap.put(MAXIMUM_HEAP_SIZE, maxHeap);
               }
               
               private void handleClassesLine(String line)
               {
                 this.classesUnloaded += 1;
                 if (this.unloadedClassComment == null) {
                   this.unloadedClassComment = line;
                 }
               }
               
               private void handlePhantomReferencesLine(String line, Matcher phantomReferences)
               {
                 double queued = Double.parseDouble(phantomReferences.group(2));
                 double cleared = Double.parseDouble(phantomReferences.group(3));
                 addDataPoint("VGCLabels.phantom.references.cleared", cleared, line);
                 addDataPoint("VGCLabels.phantom.references.queued", queued, line);
               }
               
               private void handleObjectsLine(String line, Matcher objects)
               {
                 double collectedBytes = Double.parseDouble(objects.group(4)) / 
                   0.0009765625D;
                 addDataPoint("VGCLabels.amount.freed", collectedBytes, line);
               }
               
               private void handleJNILine(String line, Matcher jniReferences) {
                 double queued = Double.parseDouble(jniReferences.group(2));
                 double cleared = Double.parseDouble(jniReferences.group(3));
                 addDataPoint("VGCLabels.jni.references.cleared", cleared, line);
                 addDataPoint("VGCLabels.jni.references.queued", queued, line);
               }
               
               protected final boolean contains(String string1, String string2)
               {
                 if (string1 != null) {
                   return string1.indexOf(string2) != -1;
                 }
                 return false;
               }
               
               protected String stringAfter(String line, String substring)
               {
                 int i2 = line.lastIndexOf(substring);
                 return line.substring(i2 + substring.length());
               }
               
               private final void tidyUpFromSystemGC()
               {
                 if (this.isSys) {
                   voidTimestamp();
                 }
               }
               
               protected void writeOutSourceData()
               {
                 DataLevel level = DataLevel.VARIANT;
                 StructuredData initialHeapData = factory.createStructuredData(
                   "InstanceISeriesVGCParser.initial.heap.properties", Messages.getString("InstanceISeriesVGCParser.initial.heap.properties"), 
                   this.initialHeapMap);
                 
                 this.sourceData.addData(initialHeapData, level);
                 
                 this.dataManager.ensureExistanceOf("VGCLabels.gc.reasons");
                 
                 super.writeOutSourceData();
               }
               
               protected boolean isTimeStampRelative()
               {
                 return false;
               }
             }


